package jmine.tec.script.persistent.dispatcher.impl;

import java.util.Collection;
import java.util.Map;

import jmine.tec.script.ScriptDispatcher;
import jmine.tec.script.ScriptExecutionContext;
import jmine.tec.script.ScriptExecutor;
import jmine.tec.script.ScriptExecutorException;
import jmine.tec.script.persistent.PersistentScriptRuntimeException;
import jmine.tec.script.persistent.ScriptPersistenceMessages;
import jmine.tec.script.persistent.context.PersistentScriptExecutionContext;
import jmine.tec.script.persistent.dispatcher.CompositeDispatcherRule;
import jmine.tec.script.persistent.dispatcher.CompositeScriptDispatcher;
import jmine.tec.utils.collection.impl.CopyOnWriteHashMap;

/**
 * Implementação de dispatcher composto.
 * 
 * @author lundberg
 */
public class CompositeScriptDispatcherImpl implements CompositeScriptDispatcher {

    private final Map<String, ScriptDispatcher> dispatchers = new CopyOnWriteHashMap<String, ScriptDispatcher>();

    /**
     * {@inheritDoc}
     */
    public <R> R dispatchExecution(ScriptExecutionContext<R> context) throws ScriptExecutorException {
        return this.findDispatcher(context).dispatchExecution(context);
    }

    /**
     * {@inheritDoc}
     */
    public <R> R dispatchGetDependencies(ScriptExecutionContext<R> context) throws ScriptExecutorException {
        return this.findDispatcher(context).dispatchGetDependencies(context);
    }

    /**
     * {@inheritDoc}
     */
    public <R> R dispatchGetValidations(ScriptExecutionContext<R> context) throws ScriptExecutorException {
        return this.findDispatcher(context).dispatchGetValidations(context);
    }

    /**
     * Encontra o dispatcher apropriado para execução do contexto.
     * 
     * @param context context
     * @return dispatcher
     */
    private ScriptDispatcher findDispatcher(ScriptExecutionContext<?> context) {
        if (!(context instanceof PersistentScriptExecutionContext)) {
            throw new PersistentScriptRuntimeException(ScriptPersistenceMessages.DISPATCHER_WRONG_CONTEXT_CLASS.create(context
                    .getScriptName()));
        }
        PersistentScriptExecutionContext ctx = (PersistentScriptExecutionContext) context;
        if (!this.dispatchers.containsKey(ctx.getDispatcherKey())) {
            throw new PersistentScriptRuntimeException(ScriptPersistenceMessages.DISPATCHER_DISPATCHER_NOT_FOUND.create(ctx
                    .getDispatcherKey()));
        }
        return this.dispatchers.get(ctx.getDispatcherKey());
    }

    /**
     * {@inheritDoc}
     */
    public void setScriptExecutors(ScriptExecutor... executors) {
        throw new UnsupportedOperationException();
    }

    /**
     * {@inheritDoc}
     */
    public void register(Collection<? extends CompositeDispatcherRule> registers) {
        for (CompositeDispatcherRule r : registers) {
            this.dispatchers.put(r.getPurpose(), r.getDispatcher());
        }
    }
}
